package com.pdg.mcplugin.simpleconomy;

import java.util.List;

import com.pdg.mcplugin.common.baseclasses.PluginClientBase;
import com.pdg.mcplugin.simpleconomy.dataproviders.accounts.AccountKey;
import com.pdg.mcplugin.simpleconomy.dataproviders.accounts.AccountValue;
import com.pdg.mcplugin.simpleconomy.dataproviders.bankmembers.BankMemberKey;
import com.pdg.mcplugin.simpleconomy.dataproviders.bankmembers.BankMemberValue;
import com.pdg.mcplugin.simpleconomy.dataproviders.banks.BankKey;
import com.pdg.mcplugin.simpleconomy.dataproviders.banks.BankValue;

import net.milkbowl.vault.economy.Economy;
import net.milkbowl.vault.economy.EconomyResponse;
import net.milkbowl.vault.economy.EconomyResponse.ResponseType;

public class Economy_SimplEconomy extends PluginClientBase<SimplEconomy> implements Economy{

	private static final String NAME = "SimplEconomy";
	private static final double AMOUNT_NONE = 0;
	private static final double BALANCE_NONE = 0;
	private static final String FORMAT_NO_SUCH_BANK = "There is no bank named '%s'.";
	private static final String FORMAT_BANK_BALANCE = "The bank '%s' has a balance of %s.";
	private static final String ERROR_NEGATIVE_BANK_DEPOSIT = "Negative bank deposits are not allowed.";
	private static final String FORMAT_BANK_DEPOSIT_RECEIPT = "You deposit %s into bank '%s'. New balance: %s";
	private static final String ERROR_NEGATIVE_BANK_WITHDRAWAL = "Negative bank withdrawals are not allowed.";
	private static final String ERROR_NEGATIVE_BANK_INQUIRY = "Negative bank inquiries are not allowed.";
	private static final String FORMAT_BANK_INSUFFICIENT_FUNDS = "Bank '%s' has less than %s.";
	private static final String FORMAT_BANK_CREATE_FAIL = "Could not create bank '%s'.";
	private static final String FORMAT_BANK_DELETE_FAILURE = "Could not delete bank '%s'.";
	private static final String ERROR_NEGATIVE_DEPOSIT = "Negative account deposits are not allowed.";
	private static final String FORMAT_NO_SUCH_ACCOUNT = "There is no account for player named '%s'.";
	private static final String ERROR_NEGATIVE_WITHDRAWAL = "Negative withdrawals are not allowed.";;
	private static final String FORMAT_NOT_A_BANK_MEMBER = "Player '%s' is not a member of bank '%s'.";
	private static final String FORMAT_NOT_BANK_OWNER = "Player '%s' is not the owner of bank '%s'.";

	public Economy_SimplEconomy(SimplEconomy simplEconomy) {
		super(simplEconomy);
	}

	@Override
	public EconomyResponse bankBalance(String theBankName) {
		BankKey theKey = new BankKey(theBankName);
		BankValue theValue = getPlugin().getDataProvider().getBankTableProvider().retrieve(theKey);
		if(theValue!=null){
			return new EconomyResponse(AMOUNT_NONE,theValue.getAmount(), ResponseType.SUCCESS, String.format(FORMAT_BANK_BALANCE,theBankName,null));
		}else{
			return new EconomyResponse(AMOUNT_NONE,BALANCE_NONE, ResponseType.FAILURE, String.format(FORMAT_NO_SUCH_BANK,theBankName));
		}
	}

	@Override
	public EconomyResponse bankDeposit(String theBankName, double theAmount) {
		if(theAmount<=AMOUNT_NONE){
			return new EconomyResponse(AMOUNT_NONE,BALANCE_NONE, ResponseType.FAILURE, ERROR_NEGATIVE_BANK_DEPOSIT);
		}
		BankKey theKey = new BankKey(theBankName);
		BankValue theValue = getPlugin().getDataProvider().getBankTableProvider().retrieve(theKey);
		if(theValue!=null){
			theValue.setAmount(theValue.getAmount()+theAmount);
			getPlugin().getDataProvider().getBankTableProvider().update(theKey, theValue);
			return new EconomyResponse(theAmount,theValue.getAmount(), ResponseType.SUCCESS, String.format(FORMAT_BANK_DEPOSIT_RECEIPT,format(theAmount),theBankName,null));
		}else{
			return new EconomyResponse(AMOUNT_NONE,BALANCE_NONE, ResponseType.FAILURE, String.format(FORMAT_NO_SUCH_BANK,theBankName));
		}
	}

	@Override
	public EconomyResponse bankHas(String theBankName, double theAmount) {
		if(theAmount<=AMOUNT_NONE){
			return new EconomyResponse(AMOUNT_NONE,BALANCE_NONE, ResponseType.FAILURE, ERROR_NEGATIVE_BANK_INQUIRY);
		}
		BankKey theKey = new BankKey(theBankName);
		BankValue theValue = getPlugin().getDataProvider().getBankTableProvider().retrieve(theKey);
		if(theValue!=null){
			if(theValue.getAmount()>=theAmount){
				return new EconomyResponse(AMOUNT_NONE,BALANCE_NONE, ResponseType.SUCCESS, null);
			}else{
				return new EconomyResponse(AMOUNT_NONE,BALANCE_NONE, ResponseType.FAILURE, String.format(FORMAT_BANK_INSUFFICIENT_FUNDS,theBankName,format(theAmount)));
			}
		}else{
			return new EconomyResponse(AMOUNT_NONE,BALANCE_NONE, ResponseType.FAILURE, String.format(FORMAT_NO_SUCH_BANK,theBankName));
		}
	}

	@Override
	public EconomyResponse bankWithdraw(String theBankName, double theAmount) {
		if(theAmount<=AMOUNT_NONE){
			return new EconomyResponse(AMOUNT_NONE,BALANCE_NONE, ResponseType.FAILURE, ERROR_NEGATIVE_BANK_WITHDRAWAL);
		}
		BankKey theKey = new BankKey(theBankName);
		BankValue theValue = getPlugin().getDataProvider().getBankTableProvider().retrieve(theKey);
		if(theValue!=null){
			theValue.setAmount(theValue.getAmount()-theAmount);
			getPlugin().getDataProvider().getBankTableProvider().update(theKey, theValue);
			return new EconomyResponse(theAmount,theValue.getAmount(), ResponseType.SUCCESS, null);
		}else{
			return new EconomyResponse(AMOUNT_NONE,BALANCE_NONE, ResponseType.FAILURE, String.format(FORMAT_NO_SUCH_BANK,theBankName));
		}
	}

	@Override
	public EconomyResponse createBank(String theBankName, String theOwner) {
		BankKey theKey = new BankKey(theBankName);
		BankValue theValue = getPlugin().getDataProvider().getBankTableProvider().retrieve(theKey);
		if(theValue==null){
			theValue = new BankValue(BALANCE_NONE);
			getPlugin().getDataProvider().getBankTableProvider().create(theKey, theValue);
			BankMemberKey theMemberKey = new BankMemberKey(theBankName,theOwner);
			BankMemberValue theMemberValue = new BankMemberValue(true);
			getPlugin().getDataProvider().getBankMemberTableProvider().create(theMemberKey, theMemberValue);
			return new EconomyResponse(AMOUNT_NONE,BALANCE_NONE, ResponseType.SUCCESS, null);
		}else{
			return new EconomyResponse(AMOUNT_NONE,BALANCE_NONE, ResponseType.FAILURE, String.format(FORMAT_BANK_CREATE_FAIL,theBankName));
		}
	}

	@Override
	public EconomyResponse deleteBank(String theBankName) {
		BankKey theKey = new BankKey(theBankName);
		if(getPlugin().getDataProvider().getBankTableProvider().delete(theKey)){
			return new EconomyResponse(AMOUNT_NONE,BALANCE_NONE, ResponseType.SUCCESS, null);
		}else{
			return new EconomyResponse(AMOUNT_NONE,BALANCE_NONE, ResponseType.FAILURE, String.format(FORMAT_BANK_DELETE_FAILURE,theBankName));
		}
	}

	@Override
	public boolean createPlayerAccount(String thePlayerName) {
		AccountKey theKey = new AccountKey(thePlayerName);
		AccountValue theValue = getPlugin().getDataProvider().getAccountTableProvider().retrieve(theKey);
		if(theValue==null){
			theValue = new AccountValue(getPlugin().getConfigurationManager().getInitialAmount(),true);
			getPlugin().getDataProvider().getAccountTableProvider().create(theKey, theValue);
			return true;
		}else{
			return false;
		}
	}

	@Override
	public String currencyNamePlural() {
		return getPlugin().getConfigurationManager().getPlural();
	}

	@Override
	public String currencyNameSingular() {
		return getPlugin().getConfigurationManager().getSingular();
	}

	@Override
	public EconomyResponse depositPlayer(String thePlayerName, double theAmount) {
		if(theAmount<=AMOUNT_NONE){
			return new EconomyResponse(AMOUNT_NONE,BALANCE_NONE, ResponseType.FAILURE, ERROR_NEGATIVE_DEPOSIT);
		}
		createPlayerAccount(thePlayerName);
		AccountKey theKey = new AccountKey(thePlayerName);
		AccountValue theValue = getPlugin().getDataProvider().getAccountTableProvider().retrieve(theKey);
		if(theValue!=null){
			theValue.setAmount(theValue.getAmount()+theAmount);
			theValue.setInitial(false);
			getPlugin().getDataProvider().getAccountTableProvider().update(theKey, theValue);
			return new EconomyResponse(theAmount,theValue.getAmount(), ResponseType.SUCCESS, null);
		}else{
			return new EconomyResponse(AMOUNT_NONE,BALANCE_NONE, ResponseType.FAILURE, String.format(FORMAT_NO_SUCH_ACCOUNT,thePlayerName));
		}
	}

	@Override
	public String format(double theAmount) {
		return String.format(getPlugin().getConfigurationManager().getFormat(),theAmount);
	}

	@Override
	public int fractionalDigits() {
		return getPlugin().getConfigurationManager().getFractionalDigits();
	}
	
	@Override
	public double getBalance(String thePlayerName) {
		createPlayerAccount(thePlayerName);
		AccountKey theKey = new AccountKey(thePlayerName);
		AccountValue theValue = getAccount(theKey);
		return theValue.getAmount();
	}

	private AccountValue getAccount(AccountKey theKey) {
		AccountValue theValue = getPlugin().getDataProvider().getAccountTableProvider().retrieve(theKey);
		if(theValue==null){
			theValue = new AccountValue(getPlugin().getConfigurationManager().getInitialAmount(),true);
			getPlugin().getDataProvider().getAccountTableProvider().create(theKey, theValue);
		}
		return theValue;
	}

	@Override
	public List<String> getBanks() {
		return getPlugin().getDataProvider().getBankTableProvider().getBanks();
	}

	@Override
	public String getName() {
		return NAME;
	}

	@Override
	public boolean has(String thePlayerName, double theAmount) {
		createPlayerAccount(thePlayerName);
		if(theAmount<=AMOUNT_NONE){
			theAmount= AMOUNT_NONE;
		}
		AccountKey theKey = new AccountKey(thePlayerName);
		AccountValue theValue = getAccount(theKey);
		if(theValue!=null){
			return theValue.getAmount()>=theAmount;
		}else{
			return false;
		}
	}

	@Override
	public boolean hasAccount(String thePlayerName) {
		AccountKey theKey = new AccountKey(thePlayerName);
		AccountValue theValue = getPlugin().getDataProvider().getAccountTableProvider().retrieve(theKey);
		return theValue!=null;
	}

	@Override
	public boolean hasBankSupport() {
		return true;
	}

	@Override
	public EconomyResponse isBankMember(String theBankName, String thePlayerName) {
		BankMemberKey theKey = new BankMemberKey(theBankName, thePlayerName);
		BankMemberValue theValue = getPlugin().getDataProvider().getBankMemberTableProvider().retrieve(theKey);
		if(theValue!=null){
			return new EconomyResponse(AMOUNT_NONE,BALANCE_NONE, ResponseType.SUCCESS, null);
		}else{
			return new EconomyResponse(AMOUNT_NONE,BALANCE_NONE, ResponseType.FAILURE, String.format(FORMAT_NOT_A_BANK_MEMBER, thePlayerName,theBankName ));
		}
	}

	@Override
	public EconomyResponse isBankOwner(String theBankName, String thePlayerName) {
		BankMemberKey theKey = new BankMemberKey(theBankName, thePlayerName);
		BankMemberValue theValue = getPlugin().getDataProvider().getBankMemberTableProvider().retrieve(theKey);
		if(theValue!=null){
			if(theValue.isOwner()){
				return new EconomyResponse(AMOUNT_NONE,BALANCE_NONE, ResponseType.SUCCESS, null);
			}else{
				return new EconomyResponse(AMOUNT_NONE,BALANCE_NONE, ResponseType.FAILURE, String.format(FORMAT_NOT_BANK_OWNER, thePlayerName,theBankName ));
			}
		}else{
			return new EconomyResponse(AMOUNT_NONE,BALANCE_NONE, ResponseType.FAILURE, String.format(FORMAT_NOT_BANK_OWNER, thePlayerName,theBankName ));
		}
	}

	@Override
	public boolean isEnabled() {
		return getPlugin().getConfigurationManager().isEnabled();
	}

	@Override
	public EconomyResponse withdrawPlayer(String thePlayerName, double theAmount) {
		createPlayerAccount(thePlayerName);
		if(theAmount<=AMOUNT_NONE){
			return new EconomyResponse(AMOUNT_NONE,BALANCE_NONE, ResponseType.FAILURE, ERROR_NEGATIVE_WITHDRAWAL);
		}
		AccountKey theKey = new AccountKey(thePlayerName);
		AccountValue theValue = getPlugin().getDataProvider().getAccountTableProvider().retrieve(theKey);
		if(theValue!=null){
			theValue.setAmount(theValue.getAmount()-theAmount);
			theValue.setInitial(false);
			getPlugin().getDataProvider().getAccountTableProvider().update(theKey, theValue);
			return new EconomyResponse(theAmount,theValue.getAmount(), ResponseType.SUCCESS, null);
		}else{
			return new EconomyResponse(AMOUNT_NONE,BALANCE_NONE, ResponseType.FAILURE, String.format(FORMAT_NO_SUCH_ACCOUNT,thePlayerName));
		}
	}

	@Override
	public boolean createPlayerAccount(String arg0, String arg1) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public EconomyResponse depositPlayer(String arg0, String arg1, double arg2) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public double getBalance(String arg0, String arg1) {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public boolean has(String arg0, String arg1, double arg2) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean hasAccount(String arg0, String arg1) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public EconomyResponse withdrawPlayer(String arg0, String arg1, double arg2) {
		// TODO Auto-generated method stub
		return null;
	}

}
